/*
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "generator.h"

Parameters::Parameters(int num, int dom, int den, int tigh, float max){
    n = num;
    m = dom;
    st = den;
    sc = tigh;
    maxV = max;

    maxConstraints = n + (n*(n-1)/2);
}

void Problem::addVar(Variable v){
    variables.push_back(v);
}

Problem * Generator::generate(){
    Problem * nProblem = new Problem();
    nProblem->setParameters(pam);
    int density_check = 0;
    //int tightness_check = 0;

    Link table;

    //gen template table for links
    for(int k = 0; k < pam.getM(); k++){
        for(int w = 0; w < pam.getM(); w++){
            table.constraint_table.insert(qMakePair(k,w),10);
        }
    }

    qsrand(QTime().currentTime().msec());
    //gen constraints
    for(int i = 0; i < pam.getN(); i++){
        QCoreApplication::processEvents();
        //Generate variable unary constraints
        QMap <int,int> unary;
        QMap <int, uint> floats;
        if(rand()%100 < pam.getSt()){
            for(int m = 0; m < pam.getM(); m++){
                int val = (int)((int)(rand()%9)+1);

                if(rand()%100 >= pam.getSc())
                    val = 0;

                unary.insert(m, val);
                //A little hacky but it does the trick
                if(!floats.contains(val))
                    floats.insert(val,0);
            }
            density_check++;
        }
        else{
            for(int m = 0; m < pam.getM(); m++){
                unary.insert(m,10);
                //A little hacky but it does the trick
                if(!floats.contains(10))
                    floats.insert(10,0);
            }
        }
        Variable var(i,unary);
        var.floats = floats;
        nProblem->addVar(var);
        for(int j = i+1; j < pam.getN(); j++){
            //gen table
            Link anew = table;
            if(rand()%100 < pam.getSt()){
                QMap<QPair<int,int>, int>::iterator it = anew.constraint_table.begin();
                while (it != anew.constraint_table.end()) {
                    int val = (int)((int)(rand()%9)+1);

                    if(rand()%100 < pam.getSc())
                        it.value() = val;
                    else
                        it.value() = 0;

                    //A little hacky but it does the trick
                    if(!anew.floats.contains(it.value()))
                        anew.floats.insert(it.value(),0);
                    ++it;
                }
                density_check++;
            }else{
                anew.floats.insert(10,0);
            }
            nProblem->constraints.insert(qMakePair(i,j),anew);
        }
    }
    return nProblem;
}

Problem * Problem::getCutHard(int alpha){
    //Set up the copied problem
    Problem * hard = new Problem(*this);
    QMap<QPair<int,int>, Link>::iterator it = hard->constraints.begin();
    while (it != hard->constraints.end()) {
        QMap<QPair<int,int>, int>::iterator iti = (*it).constraint_table.begin();
        while(iti != (*it).constraint_table.end()){
            if(iti.value() > alpha)
                iti.value() = 10;
            else
                iti.value() = 0;
            ++iti;
        }
        ++it;
    }
    for(int i = 0; i < hard->variables.size(); i++){
        QMap<int,int>::iterator it = hard->variables[i].vals.begin();
        while(it != hard->variables.at(i).vals.end()){
            if(it.value() > alpha)
                it.value() = 10;
            else
                it.value() = 0;
            ++it;
        }
    }
    return hard;
}

QMap<QPair<int,int>,Link> Problem::getLinksFor(int s){
    QMap<QPair<int,int>,Link> sub;
    for(int i = s+1; i < _pam.getN(); i++){
        sub.insert(qMakePair(s,i),constraints.find(qMakePair(s,i)).value());
    }
    return sub;
}

void Generator::setParameters(Parameters pm){
    pam = pm;
}

Parameters Generator::getParameters() const{
    return pam;
}

Problem::~Problem(){
    variables.clear();
    constraints.clear();
}
